<template>
  <div class="my-spin" :class="wrapperClasses">
    <div v-if="loading && isDelayOver" class="my-spin__loading" :class="spinClasses">
      <slot name="dot">
        <span class="my-spin__dot">
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
        <i class="my-spin__dot-item"></i>
      </span>
      </slot>

      <div class="my-spin__text">
        <slot name="text">{{tip}}</slot>
      </div>
    </div>
    <div v-if="$slots.default" class="my-spin__container" :class="containerClasses">
      <slot></slot>
    </div>
  </div>
</template>

<script>
  /**
   * 加载中
   * @module $ui/components/my-spin
   */

  /**
   * 插槽
   * @member slots
   * @property {string} default 默认插槽，定义需要显示加载的容器
   * @property {string} dot 定义加载中的内容
   */
  export default {
    name: 'MySpin',
    /**
     * 属性参数
     * @member props
     * @property {string} [size=default]  组件大小，可选值为 small default large
     * @property {number} [delay=100] 延迟显示加载效果的时间（防止闪烁）
     * @property {string} [tip] 当作为包裹元素时，可以自定义描述文案
     * @property {boolean} [loading=false] 是否为加载中状态
     * @property {boolean} [fit=false] 充满父容器
     */
    props: {
      // 组件大小，可选值为 small default large
      size: {
        type: String,
        default: 'default',
        validator(val) {
          return ['default', 'large', 'small'].includes(val)
        }
      },
      // 延迟显示加载效果的时间（防止闪烁）
      delay: {
        type: Number,
        default: 100
      },
      // 当作为包裹元素时，可以自定义描述文案
      tip: String,

      // 是否为加载中状态
      loading: Boolean,
      // 充满父容器
      fit: Boolean
    },
    data() {
      this.timerId = null
      return {
        isDelayOver: false
      }
    },
    watch: {
      loading: {
        immediate: true,
        handler(val) {
          val && this.setupLoading()
        }
      }
    },
    computed: {
      spinClasses() {
        return {
          [`is-${this.size}`]: !!this.size
        }
      },
      wrapperClasses() {
        return {
          'my-spin--nested': !!this.$slots.default,
          'is-fit': this.fit
        }
      },
      containerClasses() {
        return {
          'is-blur': (this.loading && this.isDelayOver)
        }
      }
    },
    methods: {
      setupLoading() {
        clearTimeout(this.timerId)
        this.isDelayOver = false
        if (this.delay > 0) {
          this.timerId = setTimeout(() => {
            this.isDelayOver = true
          }, this.delay)
        } else {
          this.isDelayOver = true
        }
      }
    },
    beforeDestroy() {
      clearTimeout(this.timerId)
    }
  }
</script>
<style>
.my-spin {
  display: inline-block;
  vertical-align: middle
}

.my-spin__loading {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  display: inline-block;
  text-align: center
}

.my-spin__loading.is-large .my-spin__dot {
  font-size: 40px
}

.my-spin__loading.is-large i {
  width: 20px;
  height: 20px
}

.my-spin__loading.is-large .my-spin__text {
  font-size: 1rem;
  padding-top: 5px
}

.my-spin__loading.is-small .my-spin__dot {
  font-size: 15px
}

.my-spin__loading.is-small i {
  width: 7.5px;
  height: 7.5px
}

.my-spin__loading.is-small .my-spin__text {
  font-size: 1rem
}

.my-spin__dot {
  position: relative;
  display: inline-block;
  width: 1em;
  height: 1em;
  font-size: 22px;
  transform: rotate(45deg);
  -webkit-animation: spinRotate 1.2s linear infinite;
  animation: spinRotate 1.2s linear infinite
}

.my-spin__dot-item {
  position: absolute;
  display: block;
  width: 10px;
  height: 10px;
  background-color: #1890ff;
  border-radius: 100%;
  transform: scale(.75);
  -webkit-transform-origin: 50% 50%;
  transform-origin: 50% 50%;
  opacity: .3;
  -webkit-animation: spinMove 1s linear infinite alternate;
  animation: spinMove 1s linear infinite alternate
}

.my-spin__dot-item:first-child {
  left: 0;
  top: 0
}

.my-spin__dot-item:nth-child(2) {
  top: 0;
  right: 0;
  -webkit-animation-delay: .4s;
  animation-delay: .4s
}

.my-spin__dot-item:nth-child(3) {
  right: 0;
  bottom: 0;
  -webkit-animation-delay: .8s;
  animation-delay: .8s
}

.my-spin__dot-item:nth-child(4) {
  bottom: 0;
  left: 0;
  -webkit-animation-delay: 1.2s;
  animation-delay: 1.2s
}

.my-spin__text {
  color: #1890ff;
  font-size: 1rem
}

.my-spin--nested {
  position: relative;
  display: block
}

.my-spin--nested .my-spin__loading {
  position: absolute;
  width: 100%;
  height: 100%;
  text-align: center;
  left: 0;
  top: 0;
  z-index: 2;
  display: block
}

.my-spin--nested .my-spin__loading.is-large .my-spin__dot {
  margin: -20px
}

.my-spin--nested .my-spin__loading.is-large .my-spin__text {
  margin-top: 20px;
  padding-top: 15px
}

.my-spin--nested .my-spin__loading.is-small .my-spin__dot {
  margin: -7.5px
}

.my-spin--nested .my-spin__loading.is-small .my-spin__text {
  padding-top: 5px;
  margin-top: 7.5px
}

.my-spin--nested .my-spin__dot {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -15px -10px -10px
}

.my-spin--nested .my-spin__text {
  position: absolute;
  width: 100%;
  top: 50%;
  margin-top: 15px
}

.my-spin--nested .my-spin__container {
  width: 100%
}

.my-spin--nested .my-spin__container:after {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 10;
  width: 100%;
  height: 100%;
  background: #fff;
  opacity: 0;
  -webkit-transition: all .3s;
  transition: all .3s;
  content: "";
  pointer-events: none
}

.my-spin--nested .my-spin__container.is-blur {
  opacity: .5;
  overflow: hidden;
  clear: both;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none
}

.my-spin--nested .my-spin__container.is-blur:after {
  opacity: .4;
  pointer-events: auto
}

.my-spin.is-fit {
  height: 100%;
  width: 100%;
  position: relative;
  text-align: center
}

.my-spin.is-fit .my-spin__container {
  height: 100%;
  text-align: left
}

.my-spin.is-fit .my-spin__loading {
  position: absolute;
  top: 50%;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%)
}
</style>
